package labox.innovation.gameserver.ai;

import static labox.innovation.gameserver.ai.CtrlIntention.AI_INTENTION_IDLE;
import labox.innovation.gameserver.model.L2CharPosition;
import labox.innovation.gameserver.model.L2Object;
import labox.innovation.gameserver.model.L2Skill;
import labox.innovation.gameserver.model.actor.L2Character;
import labox.innovation.gameserver.network.serverpackets.AutoAttackStart;
import labox.innovation.gameserver.network.serverpackets.AutoAttackStop;
import labox.innovation.gameserver.network.serverpackets.Die;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Mother class of all objects AI in the world.<BR>
 * <BR>
 * 
 * AbastractAI :<BR>
 * <BR>
 * <li>L2CharacterAI</li><BR>
 * <BR>
 * 
 */
public abstract class AbstractAI implements Ctrl {

	protected static final Logger _log = LoggerFactory.getLogger(AbstractAI.class.getName());

	/**
	 * AI管理的Character对象
	 */
	protected final L2Character _actor;

	/**
	 * 角色的AI连接器，AI对象通用连接器调用角色内部相应的方法
	 */
	protected final L2Character.AIAccessor _accessor;

	/**
	 * 当前的意图
	 */
	protected CtrlIntention _intention = AI_INTENTION_IDLE;

	/**
	 * 当前意图的第一个参数
	 */
	protected Object _intentionArg0;

	/**
	 * 当前意图的第二个参数
	 */
	protected Object _intentionArg1;

	/**
	 * 标记客户端的状态，为了区别发送哪一个信息
	 */
	private boolean _clientAutoAttacking;

	/**
	 * AI对象维护的各类目标
	 */
	protected L2Object _target;

	/**
	 * 施法的目标
	 */
	protected L2Character _castTarget;

	/**
	 * 攻击的目标
	 */
	protected L2Character _attackTarget;

	/**
	 * 跟随的目标
	 */
	protected L2Character _followTarget;

	/**
	 * 通过INTENTION_CAST释放的技能
	 */
	L2Skill _skill;

	/**
	 * AbstractAI的构造函数.<BR>
	 * <BR>
	 * 
	 * @param accessor
	 *            The AI accessor of the L2Character
	 * 
	 */
	protected AbstractAI(L2Character.AIAccessor accessor) {
		_accessor = accessor;

		// Get the L2Character managed by this Accessor AI
		_actor = accessor.getActor();
	}

	/**
	 * Return the L2Character managed by this Accessor AI.<BR>
	 * <BR>
	 */
	public L2Character getActor() {
		return _actor;
	}

	/**
	 * 返回当前的AI意图.<BR>
	 * <BR>
	 */
	public CtrlIntention getIntention() {
		return _intention;
	}

	protected void setCastTarget(L2Character target) {
		_castTarget = target;
	}

	/**
	 * 返回当前施法的目标.<BR>
	 * <BR>
	 */
	public L2Character getCastTarget() {
		return _castTarget;
	}

	protected void setAttackTarget(L2Character target) {
		_attackTarget = target;
	}

	/**
	 * 返回当前的攻击目标.<BR>
	 * <BR>
	 */
	public L2Character getAttackTarget() {
		return _attackTarget;
	}

	/**
	 * 设置AbstractAI的意图.<BR>
	 * <BR>
	 * 
	 * <FONT COLOR=#FF0000><B> <U>Caution</U> : This method is USED by AI classes</B></FONT><BR>
	 * <BR>
	 * 
	 * <B><U> Overridden in </U> : </B><BR>
	 * <B>L2AttackableAI</B> : Create an AI Task executed every 1s (if necessary)<BR>
	 * <B>L2PlayerAI</B> : Stores the current AI intention parameters to later restore it if necessary<BR>
	 * <BR>
	 * 
	 * @param intention
	 *            The new Intention to set to the AI
	 * @param arg0
	 *            The first parameter of the Intention
	 * @param arg1
	 *            The second parameter of the Intention
	 * 
	 */
	void changeIntention(CtrlIntention intention, Object arg0, Object arg1) {
		_intention = intention;
		_intentionArg0 = arg0;
		_intentionArg1 = arg1;
	}

	/**
	 * 根据新的意图启动角色对象新的意图方法.<BR>
	 * <BR>
	 * 
	 * <FONT COLOR=#FF0000><B> <U>Caution</U> : Stop the FOLLOW mode if necessary</B></FONT><BR>
	 * <BR>
	 * 
	 * @param intention
	 *            The new Intention to set to the AI
	 * 
	 */
	public final void setIntention(CtrlIntention intention) {
		setIntention(intention, null, null);
	}

	/**
	 * 根据新的意图启动角色对象新的意图方法.<BR>
	 * <BR>
	 * 
	 * <FONT COLOR=#FF0000><B> <U>Caution</U> : Stop the FOLLOW mode if necessary</B></FONT><BR>
	 * <BR>
	 * 
	 * @param intention
	 *            The new Intention to set to the AI
	 * @param arg0
	 *            The first parameter of the Intention (optional target)
	 * 
	 */
	public final void setIntention(CtrlIntention intention, Object arg0) {
		setIntention(intention, arg0, null);
	}

	public final void setIntention(CtrlIntention intention, Object arg0, Object arg1) {

		// Launch the onIntention method of the L2CharacterAI corresponding to the new Intention
		switch (intention) {
		case AI_INTENTION_IDLE:
			onIntentionIdle();
			break;
		case AI_INTENTION_ACTIVE:
			onIntentionActive();
			break;
		case AI_INTENTION_ATTACK:
			onIntentionAttack((L2Character) arg0);
			break;
		case AI_INTENTION_CAST:
			onIntentionCast((L2Skill) arg0, (L2Object) arg1);
			break;
		case AI_INTENTION_MOVE_TO:
			onIntentionMoveTo((L2CharPosition) arg0);
			break;
		case AI_INTENTION_FOLLOW:
			onIntentionFollow((L2Character) arg0, (Integer) arg1);
			break;
		case AI_INTENTION_PICK_UP:
			onIntentionPickUp((L2Object) arg0);
			break;
		case AI_INTENTION_INTERACT:
			onIntentionInteract((L2Object) arg0);
			break;
		}
	}

	/**
	 * 根据指定的事件启动AI相应事件方法.<BR>
	 * <BR>
	 * 
	 * <FONT COLOR=#FF0000><B> <U>Caution</U> : The current general intention won't be change (ex : If the character attack and is stunned, he will attack again after the stunned period)</B></FONT><BR>
	 * <BR>
	 * 
	 * @param evt
	 *            The event whose the AI must be notified
	 * 
	 */
	public final void notifyEvent(CtrlEvent evt) {
		notifyEvent(evt, null, null);
	}

	/**
	 * 根据指定的事件启动AI相应事件方法<BR>
	 * <BR>
	 * 
	 * <FONT COLOR=#FF0000><B> <U>Caution</U> : The current general intention won't be change (ex : If the character attack and is stunned, he will attack again after the stunned period)</B></FONT><BR>
	 * <BR>
	 * 
	 * @param evt
	 *            The event whose the AI must be notified
	 * @param arg0
	 *            The first parameter of the Event (optional target)
	 * 
	 */
	public final void notifyEvent(CtrlEvent evt, Object arg0) {
		notifyEvent(evt, arg0, null);
	}

	/**
	 * 根据指定的事件启动AI相应事件方法.<BR>
	 * <BR>
	 * 
	 * <FONT COLOR=#FF0000><B> <U>Caution</U> : 当前通常的意图不会改变 (例如 : 如果角色攻击的时候被眩晕，当他眩晕状态结束的时候会再次攻击)</B></FONT><BR>
	 * <BR>
	 * 
	 * @param evt
	 *            需要通知AI的事件
	 * @param arg0
	 *            The first parameter of the Event (optional target)
	 * @param arg1
	 *            The second parameter of the Event (optional target)
	 * 
	 */
	public final void notifyEvent(CtrlEvent evt, Object arg0, Object arg1) {
		if (!_actor.isVisible() || !_actor.hasAI())
			return;

		switch (evt) {
		case EVT_THINK:
			onEvtThink();
			break;
		case EVT_ATTACKED:
			onEvtAttacked((L2Character) arg0);
			break;
		case EVT_AGGRESSION:
			onEvtAggression((L2Character) arg0, ((Number) arg1).intValue());
			break;
		case EVT_STUNNED:
			onEvtStunned((L2Character) arg0);
			break;
		case EVT_PARALYZED:
			onEvtParalyzed((L2Character) arg0);
			break;
		case EVT_SLEEPING:
			onEvtSleeping((L2Character) arg0);
			break;
		case EVT_ROOTED:
			onEvtRooted((L2Character) arg0);
			break;
		case EVT_CONFUSED:
			onEvtConfused((L2Character) arg0);
			break;
		case EVT_MUTED:
			onEvtMuted((L2Character) arg0);
			break;
		case EVT_READY_TO_ACT:
			onEvtReadyToAct();
			break;
		case EVT_USER_CMD:
			onEvtUserCmd(arg0, arg1);
			break;
		case EVT_ARRIVED:
			// happens e.g. from stopmove but we don't process it if we're casting
			onEvtArrived();
			break;
		case EVT_ARRIVED_REVALIDATE:
			onEvtArrivedRevalidate();
			break;
		case EVT_FORGET_OBJECT:
			onEvtForgetObject((L2Object) arg0);
			break;
		case EVT_CANCEL:
			onEvtCancel();
			break;
		case EVT_DEAD:
			onEvtDead();
			break;
		case EVT_FINISH_CASTING:
			onEvtFinishCasting();
			break;
		}
	}

	/**
	 * 在服务器端移动角色到一个角色身边，通过发送Server->Client的包MoveToPawn<I>（广播）</i>.<BR>
	 * <BR>
	 * <FONT COLOR=#FF0000><B> <U>Caution</U> : Low level function, used by AI subclasses</B></FONT><BR>
	 * <BR>
	 * 
	 */
	protected void moveToPawn(L2Object pawn, int offset) {
		// Set AI movement data
		_target = pawn;
		// Calculate movement data for a move to location action and add the actor to movingObjects of GameTimeController
		_accessor.moveTo(pawn.getX(), pawn.getY(), offset);

	}

	/**
	 * 在服务器端移动角色到一个位置坐标，通过发送Server->Client的包MoveToPawn<I>（广播）.<BR>
	 * <BR>
	 * 
	 * <FONT COLOR=#FF0000><B> <U>Caution</U> : Low level function, used by AI subclasses</B></FONT><BR>
	 * <BR>
	 * 
	 */
	protected void moveTo(int x, int y) {
		// Calculate movement data for a move to location action and add the actor to movingObjects of GameTimeController
		_accessor.moveTo(x, y);

	}

	/**
	 * 在服务器端移动角色到一个位置坐标，通过发送Server->Client的包MoveToPawn<I>（广播）.<BR>
	 * <BR>
	 * 
	 * <FONT COLOR=#FF0000><B> <U>Caution</U> : Low level function, used by AI subclasses</B></FONT><BR>
	 * <BR>
	 * 
	 */
	protected void moveTo(int x, int y, int offset) {
		// Calculate movement data for a move to location action and add the actor to movingObjects of GameTimeController
		_accessor.moveTo(x, y, offset);

	}

	/**
	 * 角色是否在自动攻击中
	 * 
	 * @return
	 */
	public boolean isAutoAttacking() {
		return _clientAutoAttacking;
	}

	/**
	 * 通过发送Server->Client的包AutoAttackStart通知客户端角色进入自动战斗状态<I>（广播）。</i> <FONT COLOR=#FF0000><B> <U>Caution</U> : Low level function, used by AI subclasses</B></FONT><BR>
	 * <BR>
	 * 
	 */
	public void clientStartAutoAttack(L2Character target) {
		if (_clientAutoAttacking) {
			if (target.getObjectId() == _attackTarget.getObjectId())
				return;
		}
		setAttackTarget(target);
		_actor.broadcastPacket(new AutoAttackStart(_actor.getObjectId(), _attackTarget.getObjectId()));
		_clientAutoAttacking = true;
	}

	/**
	 * Stop the actor auto-attack client side by sending Server->Client packet AutoAttackStop <I>(broadcast)</I>.<BR>
	 * <BR>
	 * 
	 * <FONT COLOR=#FF0000><B> <U>Caution</U> : Low level function, used by AI subclasses</B></FONT><BR>
	 * <BR>
	 * 
	 */
	public void clientStopAutoAttack() {
		if (_clientAutoAttacking) {
			_actor.broadcastPacket(new AutoAttackStop(_actor.getObjectId()));
			_clientAutoAttacking = false;
		}
	}

	/**
	 * 通过发送Server->Client包AutoAttackStop，Die通知客户端角色死亡<I>(广播)</I>.<BR>
	 * <BR>
	 * <FONT COLOR=#FF0000><B> <U>Caution</U> : Low level function, used by AI subclasses</B></FONT><BR>
	 * <BR>
	 * 
	 */
	protected void clientNotifyDead() {
		// Send a Server->Client packet Die to the actor and all L2PcInstance in its _knownPlayers
		Die msg = new Die(_actor);
		_actor.broadcastPacket(msg);
		// Init AI
		_intention = AI_INTENTION_IDLE;
		//因为角色死亡所以，这里直接关闭了自动战斗的动画，不需要通知客户端停止自动战斗动画协议
		_clientAutoAttacking = false;
		_target = null;
		_castTarget = null;
		_attackTarget = null;
	}

	protected L2Character getFollowTarget() {
		return _followTarget;
	}

	protected L2Object getTarget() {
		return _target;
	}

	protected void setTarget(L2Object target) {
		_target = target;
	}

	/**
	 * 进入空闲状态的处理
	 * 
	 */
	protected abstract void onIntentionIdle();

	/**
	 * 进入警戒状态的处理
	 * 
	 */
	protected abstract void onIntentionActive();

	/**
	 * 进入攻击状态的处理
	 * 
	 * @param target
	 */
	protected abstract void onIntentionAttack(L2Character target);

	/**
	 * 进入施法状态的处理
	 * 
	 * @param skill
	 * @param target
	 */
	protected abstract void onIntentionCast(L2Skill skill, L2Object target);

	/**
	 * 进入移动状态的处理
	 * 
	 * @param destination
	 */
	protected abstract void onIntentionMoveTo(L2CharPosition destination);

	/**
	 * 进入跟随状态的处理
	 * 
	 * @param target
	 */
	protected abstract void onIntentionFollow(L2Character target, Integer offset);

	/**
	 * 进入拾取状态的处理
	 * 
	 * @param item
	 */
	protected abstract void onIntentionPickUp(L2Object item);

	/**
	 * 进入交互状态的处理
	 * 
	 * @param object
	 */
	protected abstract void onIntentionInteract(L2Object object);

	/**
	 * 下一步行动处理
	 * 
	 */
	protected abstract void onEvtThink();

	/**
	 * 遭到攻击的事件通知
	 * 
	 * @param attacker
	 */
	protected abstract void onEvtAttacked(L2Character attacker);

	/**
	 * 改变仇恨值的处理
	 * 
	 * @param target
	 * @param aggro
	 */
	protected abstract void onEvtAggression(L2Character target, int aggro);

	/**
	 * 眩晕状态处理
	 * 
	 * @param attacker
	 */
	protected abstract void onEvtStunned(L2Character attacker);

	/**
	 * 瘫痪或石化的状态处理
	 * 
	 * @param attacker
	 */
	protected abstract void onEvtParalyzed(L2Character attacker);

	/**
	 * 睡眠状态处理
	 * 
	 * @param attacker
	 */
	protected abstract void onEvtSleeping(L2Character attacker);

	/**
	 * 盘绕状态处理
	 * 
	 * @param attacker
	 */
	protected abstract void onEvtRooted(L2Character attacker);

	protected abstract void onEvtConfused(L2Character attacker);

	protected abstract void onEvtMuted(L2Character attacker);

	protected abstract void onEvtReadyToAct();

	protected abstract void onEvtUserCmd(Object arg0, Object arg1);

	protected abstract void onEvtArrived();

	protected abstract void onEvtArrivedRevalidate();

	protected abstract void onEvtForgetObject(L2Object object);

	protected abstract void onEvtCancel();

	protected abstract void onEvtDead();

	protected abstract void onEvtFinishCasting();

}
